from Base import *

class CHeader(CItem):
    _gName = "Header"
    def __init__(self, name = _gName):
        super(CHeader,self).__init__(name)
        self._headerLength = 0
        #the length indicated in header
        #it may include header, may not, depend on the protocol
        self._length = 0

    def GetHeader(self):
        return self._rawStr

    def GetLength(self):
        return self._length

    def GetHeaderLength(self):
        return self._headerLength


class CAppHeader(CHeader):
    '''The application header'''
    _gName = "Application Header"

    #the sub item name
    _gNameAppId = "Application ID" 
    _gNameMsgType = "Message Type" 
    _gNameMsgCtrlFlag = "Message Control Flag" 
    _gNameMsgLen = "Message Length" 

    _gMaskAppId = 0x3F  # mask for application identifier
    _gMaskNonStdFlag = 0x40  # mask for non-standard flag in MsgType and AppId
    _gMaskTestFlag = 0x20    # mask for Test message flag
    _gMaskMsgType = 0x1F  # mask for message type
    _gMaskVersion = 0x70  # mask for version 
    _gMaskVersionFlag = 0x80 
    _gShiftVersionFlag = 7 
    _gShiftNonStdFlag = 6 
    _gShiftTestFlag = 5 
    _gMaskMoreFlag = 0x80 
    _gMaskMsgCtrlFlag = 0x0F  # mask for message control flag
    _gMask16BitMsgLength = 0x02  # mask for 16bit message length bit
    _gMaskResponseExpected = 0x01  # mask for response expected  
    _gMaskPriorityFlag = 0x03 
    _gShiftVersion = 4  # shift value for version
    _gMaskFirstMoreBit = 0x20  	# mask for first more-bit
    _gMaskMoreBit = 0x80  		# mask for all other more-bits 
    _gMaskFirstLength = 0x1F 		# mask for first length-value
    _gMaskLength = 0x7F 			# mask for all other length-values   
    _gMaxLengthOn8Bits = 0xFF

    def __init__(self,name=_gName):
        super(CAppHeader, self).__init__(name)
        self._appId = 0
        self._msgType = 0
        self._hlColor = 'VertSplit'

    def GetAppId(self):
        return self._appId

    def GetMsgType(self):
        return self._msgType

    def InitSubItem(self):
        name = self._gNameAppId
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameMsgType
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameMsgCtrlFlag
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

        name = self._gNameMsgLen
        item = CItem(name)
        self._subList[name] = item
        self._nameList.append(name)

    def Parse(self, dataStr):
        #first initialize the sub item list
        self.InitSubItem()

        self._startIndex = dataStr.GetIndex()
        headerLength = 0

        #reading fisrt byte, save application ID
        value = dataStr.GetByte()
        headerLength = headerLength+1
        self._appId = value & self._gMaskAppId
        item = self._subList[self._gNameAppId]
        item._rawStr = DATA_FORMAT.format(self._appId)

        #reading second byte, save message type
        value = dataStr.GetByte()
        headerLength = headerLength+1
        self._nonStandardFlag = (value & self._gMaskNonStdFlag) >> self._gShiftNonStdFlag
        self._testFlag = (value & self._gMaskTestFlag) >> self._gShiftTestFlag
        self._msgType = value & self._gMaskMsgType
        item = self._subList[self._gNameMsgType]
        item._rawStr = DATA_FORMAT.format(self._msgType)

        #reading third byte, saving version
        value = dataStr.GetByte()
        headerLength=headerLength+1
        self._versionFlag = (value & self._gMaskVersionFlag) >> self._gShiftVersionFlag
        self._version = (value & self._gMaskVersion) >> self._gShiftVersion
        self._msgCtrlFlag = value & self._gMaskMsgCtrlFlag 
        item = self._subList[self._gNameMsgCtrlFlag]
        item._rawStr = HEX_DATA_FORMAT.format(self._msgCtrlFlag)

        # if there's a fourth byte with a priority flag, we save it
        if(self._versionFlag):
            value = dataStr.GetByte()
            headerLength=headerLength+1
            self._priority = value & self._gMaskPriorityFlag

        #reading  saving payload length and header length
        value = dataStr.GetByte()
        headerLength=headerLength+1
        if(self._msgCtrlFlag & self._gMask16BitMsgLength):
            #length bit is set, means it has 16bit length
            length = value << 8
            value = dataStr.GetByte()
            headerLength=headerLength+1
            length = length | value
        else:
            length = value
        self._length = length
        self._headerLength = headerLength

        item = self._subList[self._gNameMsgLen]
        item._rawStr = HEX_DATA_FORMAT.format(self._length)
        item._infoStr = DATA_FORMAT.format(self._length)

        self._rawStr = DATA_STRING_FORMAT.format(dataStr.GetString(self._startIndex, self._startIndex + headerLength))





        #end of parse()

class CEleHeader(CHeader):
    '''Header of information element'''
    _gName = "Element Header"

    _gMaskId = 0xC0 				# mask for identifier
    _gMaskFirstMoreBit = 0x20 	# mask for first more
    _gMaskMoreBit = 0x80 		# mask for all other more-
    _gMaskFirstLength = 0x1F		# mask for first length-
    _gMaskLength = 0x7F			# mask for all other length-v
    _gShiftId = 6 				# shift value for identi
    _gShiftFirstMoreBit = 5		# shift value for first mor
    _gShiftMoreBit = 7			# shift value for all other more-b
    _gMaxLengthOn5Bits = 0
    _gMaxLengthOn12Bits = 0x0FFF

    def __init__(self,name=_gName, recommendedLen = -1):
        super(CEleHeader, self).__init__(name)
        #if the recommendedLen is not -1, it means we should check the length value
        self._recommendedLen = recommendedLen


    def Parse(self, dataStr):
        self._startIndex = dataStr.GetIndex()
        headerLength = 0

        value = dataStr.GetByte()
        headerLength = headerLength+1
        self._id = value & self._gMaskId

        length = value & self._gMaskFirstLength
        if(value & self._gMaskFirstMoreBit):
            value = dataStr.GetByte()
            headerLength=headerLength+1
            length = length << 7
            length = length | (value & self._gMaskLength)
            if(value & self._gMaskMoreBit):
                value = dataStr.GetByte()
                headerLength=headerLength+1
                length = length << 7
                length = length | (value & self._gMaskLength)
        self._length = length
        self._headerLength = headerLength

        hdString = dataStr.GetString(self._startIndex, self._startIndex + headerLength)
        self._rawStr = DATA_STRING_FORMAT.format(hdString)
        self._infoStr = "length:" + DATA_FORMAT.format(self._length)


        if (self._recommendedLen != -1):
            if (self._recommendedLen != self._length):
                self._errStr = "Invalid length"


        #end of Parse()


